using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;

namespace NQueries.Utils
{
    /// <summary>
    /// Contains various methods for checking input parameters.
    /// </summary>
    internal static class Check
    {
        /// <summary>
        /// Checks if the count of the <see cref="IEnumerable{T}"/> is in the specified range.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="enumerable"></param>
        /// <param name="min"></param>
        /// <param name="max"></param>
        /// <param name="argumentName"></param>
        public static void ElementCountInRange<T>([ValidatedNotNull] IEnumerable<T> enumerable, int min, int max, string argumentName)
        {
            IsNotNull(enumerable, argumentName);
            int count = enumerable.Count();
            if (count < min || count > max)
                throw new ArgumentOutOfRangeException("the number of items <{0}> is not in the expected range min <{1}> max <{2}>".FormatWith(count, min, max), argumentName);
        }

        /// <summary>
        /// Makes sure the parameter is not null.
        /// </summary>
        /// <param name="value"></param>
        /// <param name="name"></param>
        [DebuggerStepThrough]
        public static void IsNotNull([ValidatedNotNull] object value, string name)
        {
            if (value == null)
                throw new ArgumentNullException(name);
        }

        /// <summary>
        /// Checks ifthe string is null or empty.
        /// </summary>
        /// <param name="argument"></param>
        /// <param name="argumentName"></param>
        public static void IsNotNullOrEmpty(string argument, string argumentName)
        {
            if (string.IsNullOrEmpty(argument))
                throw new ArgumentNullException(argumentName, "string is null or empty");
        }

        /// <summary>
        /// Checks if <paramref name="argument"/> is of type <paramref name="baseType"/>.
        /// </summary>
        /// <param name="argument"></param>
        /// <param name="baseType"></param>
        /// <param name="argumentName"></param>
        [DebuggerStepThrough]
        public static void IsOfType(object argument, Type baseType, string argumentName)
        {
            IsNotNull(argument, argumentName);
            IsNotNull(baseType, "baseType");

            if (!baseType.IsInstanceOfType(argument))
                throw new ArgumentException("{0} is not of type {1}.".FormatWith(argument, baseType), argumentName);
        }
    }
}